#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"

namespace MyRpc
{
    namespace server
    {
        enum class ParaType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,  // 浮点型数据类型
            STRING,
            ARRAY,
            OBJECT
        };

        using MethodCallBack = std::function<void(const Json::Value&, Json::Value&)>; // 第一个对象是调用方法传来的参数 第二个参数是返回的参数
        using ParamDescribe = std::pair<std::string, ParaType>;
        
        // 这是一个注册中心的接口 注册服务给注册中心
        class ServiceDescribe  // 这个类是对一个方法的描述
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            // 传递右值用万能应用接口
            ServiceDescribe(std::string&& name, MethodCallBack&& handler, std::vector<ParamDescribe>&& paras,
                ParaType result)
                :_method_name(std::move(name))
                ,_mcb(std::move(handler))
                ,_para_manage(std::move(paras))
                ,_result_type(result)
            {}
            const std::string& method()  { return _method_name; }
            bool paramCheck(const Json::Value& para)  // 通过传过来的参数进行参数检验
            {
                for(const auto& e : _para_manage)
                {
                    if(para.isMember(e.first) == false)
                    {
                        LOG(DEBUGLEVEL, "没有找到这个参数类型 检验失败!");
                        return false;
                    }
                    // 接下来继续判断参数类型是否匹配
                    if(check(e.second, para[e.first]) == false)
                    {
                        LOG(DEBUGLEVEL, "这个参数和规定的参数不匹配 检验失败!");
                        return false;
                    }
                }
                return true;
            }
            bool resultCheck(const Json::Value& res)
            {
                return check(_result_type, res);
            }

            // 回调函数调用
            bool call(const Json::Value& req, Json::Value& res)
            {
                _mcb(req, res);
                return check(_result_type, res);
            }
        private:
            bool check(const ParaType& type, const Json::Value& para)
            {
                switch(type)
                {
                    case ParaType::BOOL : return para.isBool();
                    case ParaType::INTEGRAL : return para.isIntegral();
                    case ParaType::NUMERIC : return para.isNumeric();
                    case ParaType::STRING : return para.isString();
                    case ParaType::ARRAY : return para.isArray();
                    case ParaType::OBJECT : return para.isObject();
                }
                return false;
            }
        private:
            std::string _method_name;  // 方法名
            MethodCallBack _mcb;
            std::vector<ParamDescribe> _para_manage;  // 用来保存每一个对象的类型 用来进行检验
            ParaType _result_type;
        };

        // 用来生成一个方法的对象工厂
        class MethodFactory
        {
        public:
            void setMethodName(const std::string& name)
            {
                _method_name = name;
            }
            void setMethodCallBack(const MethodCallBack& cb)
            {
                _mcb = cb;
            }
            void setParam(const std::string& desc, const ParaType& ptype)
            {
                _para_manage.push_back(ParamDescribe(desc, ptype));
            }
            void setResultType(const ParaType& restype)
            {
                _result_type = restype;
            }
            ServiceDescribe::ptr build()
            {
                // 为了保持他们的右值属性 这里也需要用move转为右值
                return std::make_shared<ServiceDescribe>(std::move(_method_name), std::move(_mcb), std::move(_para_manage), _result_type);
            }
        private:
            std::string _method_name;  // 方法名
            MethodCallBack _mcb;
            std::vector<ParamDescribe> _para_manage;  // 用来保存每一个对象的类型 用来进行检验
            ParaType _result_type;
        };

        class ServiceManage
        {
        public:
            using ptr = std::shared_ptr<ServiceManage>;
            void insert(const ServiceDescribe::ptr& method)  // 新增一个方法
            {
                std::lock_guard<std::mutex> lock(_mutex);
                // LOG(DEBUGLEVEL, "正在进行插入方法过程")
                _method_manage.insert(std::make_pair(method->method(), method));
            }
            ServiceDescribe::ptr select(const std::string& method_name)  // 查找返回一个方法
            {
                auto it = _method_manage.find(method_name);
                if(it == _method_manage.end())
                {
                    LOG(DEBUGLEVEL, "没有找到这个方法 查找失败!");
                    return ServiceDescribe::ptr();
                }
                // 走到这块就是找到啦
                return it->second;
            }

            void remove(const std::string& method_name)  // 删除一个方法
            {
                std::lock_guard<std::mutex> lock(_mutex);
                auto it = _method_manage.find(method_name);
                if(it == _method_manage.end())
                {
                    LOG(DEBUGLEVEL, "没有找到这个方法 删除失败!");
                    return;
                }
                _method_manage.erase(method_name);
            }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _method_manage;
        };

        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter()
                :_manage(std::make_shared<ServiceManage>())
            {}
            // 这个接口是提供给 dispatcher 的接口
            void OnRpcMessage(const BaseConnection::ptr& conn, const RpcRequest::ptr& msg)
            {
                // 先再方法管理中找到有没有这个方法
                auto it = _manage->select(msg->method()).get();
                if(it == nullptr)
                {
                    LOG(DEBUGLEVEL, "没有找到这个服务 处理失败!");
                    response(conn, msg, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                    return;
                }
                // 调用服务之前应该先判断参数是否合适
                if(it->paramCheck(msg->parameters()) == false)
                {
                    LOG(DEBUGLEVEL, "参数检验不匹配 无法调用服务!");
                    response(conn, msg, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                    return;
                }
                Json::Value resp;
                // 调用这个服务
                bool flag = it->call(msg->parameters(), resp);
                if(flag == false)
                {
                    LOG(DEBUGLEVEL, "调用函数失败!");
                    response(conn, msg, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                    return;
                }
                // 走到这块返回正确的的应答
                response(conn, msg, resp, RCode::RCODE_OK);
            }
            void registerMethod(const ServiceDescribe::ptr& method)
            {
                // LOG(DEBUGLEVEL, "进入注册方法部分");
                return _manage->insert(method);
            }
        private:
            void response(const BaseConnection::ptr& conn, const RpcRequest::ptr& msg, const Json::Value& result, RCode rcode)
            {
                auto resp = MessageFactory::create<RpcResponse>();
                resp->setMType(MyRpc::MType::RSP_RPC);
                resp->setId(msg->id());
                resp->setRcode(rcode);
                resp->setResult(result);
                // 构造完一个请求应答之后 进行发送
                conn->send(resp);
            }
        private:
            ServiceManage::ptr _manage;
        };
    }
}